package com.slipper.system.controller;

import com.slipper.constants.Constants;
import com.slipper.core.tree.Node;
import com.slipper.core.tree.Tree;
import com.slipper.core.tree.TreeInfo;
import com.slipper.core.tree.TreeUtil;
import com.slipper.system.codeless.bo.PageBO;
import com.slipper.system.codeless.bo.PageCompBO;
import com.slipper.system.codeless.bo.PageCompButtonBO;
import com.slipper.system.codeless.service.PageCompButtonService;
import com.slipper.system.codeless.service.PageCompService;
import com.slipper.system.codeless.service.PageService;
import com.slipper.system.menu.service.MenuPrivilegeService;
import com.slipper.system.menu.service.MenuService;
import com.slipper.system.role.service.RoleService;
import com.slipper.system.subsystem.bo.SubsystemBO;
import com.slipper.system.menu.bo.MenuBO;
import com.slipper.system.menu.bo.MenuPrivilegeBO;
import com.slipper.system.role.bo.RoleBO;
import com.slipper.system.subsystem.service.SubsystemService;
import com.slipper.util.*;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

@RestController
@RequestMapping("/system/role")
public class CodelessRoleController {
    @Resource
    private RoleService roleService;
    @Resource
    private MenuService menuService;
    @Resource
    private SubsystemService subsystemService;
    @Resource
    private MenuPrivilegeService menuPrivilegeService;
    @Resource
    private PageService pageService;
    @Resource
    private PageCompService pageCompService;
    @Resource
    private PageCompButtonService pageCompButtonService;

    @PostMapping("/queryPower")
    public String queryPower(@RequestBody RoleBO bo) {
        Map<String, Object> model = new HashMap<>();
        model.put("rolePrivilege", this.roleService.queryPower(bo));

        // 查询所有子系统
        SubsystemBO subsystemQO = new SubsystemBO();
        subsystemQO.setType(Constants.Subsystem.TYPE_SUBSYSTEM);
        List<SubsystemBO> subsystemList = subsystemService.queryList(subsystemQO);
        TreeInfo subsystemInfo = new TreeInfo("子系统");
        subsystemInfo.setRootId(Constants.ROOT_ID);
        subsystemInfo.setIdField("id");
        subsystemInfo.setPidField(null);
        subsystemInfo.setNodeType("subsystem");
        subsystemInfo.setTextField("name");
        subsystemInfo.setSortField("ordinal");

        // 查询所有菜单
        MenuBO menuQO = new MenuBO();
        menuQO.setSubsystem(Constants.Subsystem.TYPE_SUBSYSTEM);
        List<MenuBO> menuList = this.menuService.queryList(menuQO);
        menuList.stream()
                .filter(menu -> Constants.ROOT_ID.equals(menu.getParentId()))
                .forEach(menu -> menu.setParentId(menu.getSubsystemId()));
        TreeInfo menuInfo = new TreeInfo("菜单");
        menuInfo.setRootId(Constants.ROOT_ID);
        menuInfo.setIdField("id");
        menuInfo.setPidField("parentId");
        menuInfo.setNodeType("menu");
        menuInfo.setTextField("name");
        menuInfo.setSortField("ordinal");

        // 查询所有菜单权限
        MenuPrivilegeBO menuPrivilegeQO = new MenuPrivilegeBO();
        menuPrivilegeQO.setSubsystem(Constants.YES);
        List<MenuPrivilegeBO> menuPrivilegeList = this.menuPrivilegeService.queryList(menuPrivilegeQO);
        TreeInfo menuPrivilegeInfo = new TreeInfo("权限");
        menuPrivilegeInfo.setRootId(Constants.ROOT_ID);
        menuPrivilegeInfo.setIdField("id");
        menuPrivilegeInfo.setPidField("menuId");
        menuPrivilegeInfo.setNodeType("privilege");
        menuPrivilegeInfo.setTextField("name");
        menuPrivilegeInfo.setSortField("ordinal");

        // 查询所有页面
        List<PageBO> pageList = this.pageService.queryList(new PageBO());
        BeanUtil.setOrdinal(pageList);

        // 查询所有页面组件
        List<PageCompBO> pageCompList = this.pageCompService.queryList(new PageCompBO());

        // 查询所有页面组件关联的页面
        Map<String, String> compPageMap = this.pageCompService.queryCompPageList();

        // 查询所有页面按钮
        List<PageCompButtonBO> buttonList = this.pageCompButtonService.queryList(new PageCompButtonBO());

        List<PageBO> menuPageList = new ArrayList<>();
        List<PageCompBO> menuCompList = new ArrayList<>();
        List<PageCompButtonBO> menuButtonList = new ArrayList<>();
        Set<String> pageIdSet = new HashSet<>();
        menuList.stream()
                .filter(menu -> Tool.isNotBlank(menu.getPageId()))
                .forEach(menu -> fillId(
                        pageIdSet,
                        menu.getPageId(),
                        menu.getId(),
                        pageList,
                        pageCompList,
                        compPageMap,
                        buttonList,
                        menuPageList,
                        menuCompList,
                        menuButtonList));

        TreeInfo pageInfo = new TreeInfo("页面");
        pageInfo.setRootId(Constants.ROOT_ID);
        pageInfo.setIdField("id");
        pageInfo.setPidField("parentId");
        pageInfo.setNodeType("page");
        pageInfo.setTextField("name");
        pageInfo.setSortField("ordinal");

        TreeInfo pageCompInfo = new TreeInfo("组件");
        pageCompInfo.setRootId(Constants.ROOT_ID);
        pageCompInfo.setIdField("id");
        pageCompInfo.setPidField("pageId");
        pageCompInfo.setNodeType("comp");
        pageCompInfo.setTextField("name");
        pageCompInfo.setSortField("ordinal");

        TreeInfo pageCompButtonInfo = new TreeInfo("按钮");
        pageCompButtonInfo.setRootId(Constants.ROOT_ID);
        pageCompButtonInfo.setIdField("id");
        pageCompButtonInfo.setPidField("compId");
        pageCompButtonInfo.setNodeType("button");
        pageCompButtonInfo.setTextField("name");
        pageCompButtonInfo.setSortField("ordinal");

        Node menuTree = TreeUtil.buildTree(
                "asc",
                new Tree(subsystemInfo, subsystemList),
                new Tree(menuInfo, menuList),
                new Tree(menuPrivilegeInfo, menuPrivilegeList),
                new Tree(pageInfo, menuPageList),
                new Tree(pageCompInfo, menuCompList),
                new Tree(pageCompButtonInfo, menuButtonList));
        model.put("menuTree", menuTree);

        Node pageTree = TreeUtil.buildTree(
                "asc",
                new Tree(pageInfo, pageList),
                new Tree(pageCompInfo, pageCompList),
                new Tree(pageCompButtonInfo, buttonList));
        model.put("pageTree", pageTree);
        return ResultUtil.successResult(model);
    }

    private void fillId(
            Set<String> pageIdSet,
            String pageId,
            String id,
            List<PageBO> pageList,
            List<PageCompBO> pageCompList,
            Map<String, String> compPageMap,
            List<PageCompButtonBO> buttonList,
            List<PageBO> menuPageList,
            List<PageCompBO> menuCompList,
            List<PageCompButtonBO> menuButtonList) {
        if (!pageIdSet.add(id + "@" + pageId) || isCircle(id, pageId)) return;

        pageList.stream().filter(page -> page.getId().equals(pageId)).forEach(page -> {
            PageBO pageBO = new PageBO();
            pageBO.setId(id + "@" + page.getId());
            pageBO.setParentId(id);
            pageBO.setName(page.getName());
            pageBO.setOrdinal(page.getOrdinal());
            menuPageList.add(pageBO);

            pageCompList.stream()
                    .filter(comp -> page.getId().equals(comp.getPageId()))
                    .forEach(comp -> {
                        PageCompBO pageCompBO = new PageCompBO();
                        pageCompBO.setId(id + "@" + page.getId() + "@" + comp.getId());
                        pageCompBO.setPageId(id + "@" + page.getId());
                        pageCompBO.setName(comp.getName());
                        pageCompBO.setOrdinal(comp.getOrdinal());
                        menuCompList.add(pageCompBO);

                        String compPageId = compPageMap.get(comp.getId());
                        if (Tool.isNotBlank(compPageId)) {
                            fillId(
                                    pageIdSet,
                                    compPageId,
                                    id + "@" + page.getId() + "@" + comp.getId(),
                                    pageList,
                                    pageCompList,
                                    compPageMap,
                                    buttonList,
                                    menuPageList,
                                    menuCompList,
                                    menuButtonList);
                        }

                        buttonList.stream()
                                .filter(button -> comp.getId().equals(button.getCompId()))
                                .forEach(button -> {
                                    PageCompButtonBO pageCompButtonBO = new PageCompButtonBO();
                                    pageCompButtonBO.setId(id + "@" + page.getId() + "@" + comp.getId() + "@" + button.getId());
                                    pageCompButtonBO.setCompId(id + "@" + page.getId() + "@" + button.getCompId());
                                    pageCompButtonBO.setName(button.getName());
                                    pageCompButtonBO.setOrdinal(-1000 + (button.getOrdinal() == null ? 0 : button.getOrdinal()));
                                    menuButtonList.add(pageCompButtonBO);

                                    String buttonPageId = compPageMap.get(button.getId());
                                    if (Tool.isNotBlank(buttonPageId)) {
                                        fillId(
                                                pageIdSet,
                                                buttonPageId,
                                                id + "@" + page.getId() + "@" + comp.getId() + "@" + button.getId(),
                                                pageList,
                                                pageCompList,
                                                compPageMap,
                                                buttonList,
                                                menuPageList,
                                                menuCompList,
                                                menuButtonList);
                                    }
                                });
                    });
        });
    }

    private boolean isCircle(String idList, String pageId) {
        if (idList.length() < 20 || pageId.length() < 20) return false;
        String[] ids = idList.split("@");
        return Arrays.asList(ids).contains(pageId);
    }
}
